﻿using DataType;
using DataType.CustomEnumType;
using DataType.JudgeResults;
using DataType.MessageType;
using MapCalclator;
using OprsSimulator.OprAttributes;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OprsSimulator.Operators
{
    public class DroneOpr : IOperator, ICommonAttris, IMoveAttris, IReconnaissanceAttris, IStateAttris
    {
        //ICommonAttris
        private int obj_id;
        private string name;
        private Color color;
        private OprType type;
        private OprSubType sub_type;
        private int value;
        private int blood;
        private int max_blood;

        public int ObjID { get => obj_id; }
        public string Name { get => name; }

        public Color Color { get => color; }

        public OprType Type { get => type; }

        public OprSubType Subtype { get => sub_type; }

        public int Value { get => value; }

        public int Blood { get => blood; set => blood = value; }

        public int MaxBlood { get => max_blood; }
        //IMoveAttris
        private int basic_speed;
        private MoveStateType move_state;
        private int cur_hex;
        private float cur_pos;
        private int speed;
        private int move_to_stop_remain_time;
        private bool can_to_move;
        private bool flag_force_stop;
        private bool stop;
        private List<int> move_path;
        private int tire;
        private int tire_accumulate_time;
        private bool on_board;
        private int car;
        private int launcher;
        private int get_on_remain_time;
        private List<int> get_on_partner_id;
        private int get_off_remain_time;
        private List<int> get_off_partner_id;
        private int change_state_remain_time;
        private MoveStateType target_state;

        public int BasicSpeed { get => basic_speed; }

        public MoveStateType MoveState { get => move_state; set => move_state = value; }
        public int CurHex { get => cur_hex; set => cur_hex = value; }
        public float CurPos { get => cur_pos; set => cur_pos = value; }
        public int Speed { get => speed; set => speed = value; }
        public int MoveToStopRemainTime { get => move_to_stop_remain_time; set => move_to_stop_remain_time = value; }
        public bool CanToMove { get => can_to_move; set => can_to_move = value; }
        public bool FlagForceStop { get => flag_force_stop; set => flag_force_stop = value; }
        public bool Stop { get => stop; set => stop = value; }
        public List<int> MovePath { get => move_path; set => move_path = value; }
        public int Tire { get => tire; set => tire = value; }
        public int TireAccumulateTime { get => tire_accumulate_time; set => tire_accumulate_time = value; }
        public bool OnBoard { get => on_board; set => on_board = value; }
        public int Car { get => car; set => car = value; }
        public int Launcher { get => launcher; set => launcher = value; }
        public int GetOnRemainTime { get => get_on_remain_time; set => get_on_remain_time = value; }
        public List<int> GetOnPartnerId { get => get_on_partner_id; set => get_on_partner_id = value; }
        public int GetOffRemainTime { get => get_off_remain_time; set => get_off_remain_time = value; }
        public List<int> GetOffPartnerId { get => get_off_partner_id; set => get_off_partner_id = value; }
        public int ChangeStateRemainTime { get => change_state_remain_time; set => change_state_remain_time = value; }
        public MoveStateType TargetState { get => target_state; set => target_state = value; }
        //IReconnaissanceAttris
        private Dictionary<OprSubType, int> observe_distance;
        private List<int> see_enemy_bop_ids;
        public Dictionary<OprSubType, int> ObserveDistance { get => observe_distance; }

        public List<int> SeeEnemyBopIDs { get => see_enemy_bop_ids; set => see_enemy_bop_ids = value; }
        //IStateAttris
        private bool stack;
        private bool keep;
        private int keep_remain_time;
        private bool lose_control;
        private int alive_remain_time;
        public bool Stack { get => stack; set => stack = value; }
        public bool Keep { get => keep; set => keep = value; }
        public int KeepRemainTime { get => keep_remain_time; set => keep_remain_time = value; }
        public bool LoseControl { get => lose_control; set => lose_control = value; }
        public int AliveRemainTime { get => alive_remain_time; set => alive_remain_time = value; }

        public void SetUp(OperatorMsg operatorMsg)
        {
            //ICommonAttris
            obj_id = operatorMsg.obj_id;
            name = operatorMsg.name;
            color = (Color)operatorMsg.color;
            type = (OprType)operatorMsg.type;
            sub_type = (OprSubType)operatorMsg.sub_type;
            value = operatorMsg.value;
            blood = operatorMsg.blood;
            max_blood = operatorMsg.max_blood;
            //IMoveAttris
            basic_speed = operatorMsg.basic_speed;
            move_state = (MoveStateType)operatorMsg.move_state;
            cur_hex = operatorMsg.cur_hex;
            cur_pos = operatorMsg.cur_pos;
            speed = operatorMsg.speed;
            move_to_stop_remain_time = operatorMsg.move_to_stop_remain_time;
            can_to_move = operatorMsg.can_to_move;
            flag_force_stop = operatorMsg.flag_force_stop;
            stop = operatorMsg.stop;
            move_path = operatorMsg.move_path;
            tire = operatorMsg.tire;
            tire_accumulate_time = operatorMsg.tire_accumulate_time;
            on_board = operatorMsg.on_board;
            car = operatorMsg.car;
            launcher = operatorMsg.launcher;
            get_on_remain_time = operatorMsg.get_on_remain_time;
            get_on_partner_id = operatorMsg.get_on_partner_id;
            get_off_remain_time = operatorMsg.get_off_remain_time;
            get_off_partner_id = operatorMsg.get_off_partner_id;
            change_state_remain_time = operatorMsg.change_state_remain_time;
            target_state = (MoveStateType)operatorMsg.target_state;
            //IReconnaissanceAttris
            if (operatorMsg.observe_distance == null)
            {
                observe_distance = new Dictionary<OprSubType, int>
                {
                    {OprSubType.Tank, 2},
                    {OprSubType.IFV, 2},
                    {OprSubType.Infantry, 2},
                    {OprSubType.Artillery, 2},
                    {OprSubType.UGV, 2},
                    {OprSubType.Drone, 0},
                    {OprSubType.Helicopter, 0},
                    {OprSubType.CruisingMissile, 0},
                };
            }
            else
            {
                foreach (var od in operatorMsg.observe_distance)
                {
                    observe_distance.Add((OprSubType)od.Key, od.Value);
                }
            }
            see_enemy_bop_ids = operatorMsg.see_enemy_bop_ids;
            //IStateAttris
            stack = operatorMsg.stack;
            keep = operatorMsg.keep;
            keep_remain_time = operatorMsg.keep_remain_time;
            lose_control = operatorMsg.lose_control;
            alive_remain_time = operatorMsg.alive_remain_time;
        }
        public void UpdataStandaloneAttris(List<IJudgeResult> judge_results, Map map)
        {
            foreach (IJudgeResult judge_result in judge_results)
            {
                if (!judge_result.IsSuccess) continue;  // 每个子方法中不需要在检查这个条件了

                if (judge_result.ObjID != obj_id) continue;  // 每个子方法中不需要在检查这个条件了
                if (judge_result.ActionType == ActionType.Move) UpdataMoveAttris(judge_result, map);
                if (judge_result.ActionType == ActionType.StopMove) UpdataStopMoveAttris(judge_result);
            }
            PutForwardObservation(map);
        }
        public void UpdateAssociatedAttris(List<IOperator> oprs, Map map)
        {
            UpdataSeeEnemyAttris(oprs, map);
        }
        public Dictionary<int, List<ActionMsg>> ConfirmValidActions(List<OperatorMsg> oprs, CityMsg[] cities, Map map, ShootJudgeTable shootJudgeTable)
        {
            Dictionary<int, List<ActionMsg>> individualValidActions = new Dictionary<int, List<ActionMsg>>();

            // 判断算子是否能机动
            bool move_flag = true;  // 能够机动的标识
            List<ActionMsg> move_action = new List<ActionMsg>();
            if (speed > 0) move_flag = false;   //未停下的算子不可机动
            if (!can_to_move && move_to_stop_remain_time > 0) move_flag = false;
            if (move_flag)
            {
                move_action.Add(new ActionMsg { type = (int)ActionType.Move, obj_id = obj_id });
                individualValidActions.Add((int)ActionType.Move, move_action);
            }

            // 判断能否停止机动
            if (speed > 0)
            {
                List<ActionMsg> stop_move_action = new List<ActionMsg>();
                stop_move_action.Add(new ActionMsg { type = (int)ActionType.StopMove, obj_id = obj_id });
                individualValidActions.Add((int)ActionType.StopMove, stop_move_action);
            }
            return individualValidActions;
        }
        private void PutForwardObservation(Map map)
        {
            // 修改机动属性
            if (speed > 0 && move_path.Count > 0)
            {
                float percetage = (float)speed / 3.6f / (float)map.Width;
                cur_pos += percetage;
                if (cur_pos >= 1)  // 到达了下一格
                {
                    cur_pos = 0;
                    cur_hex = move_path[0];
                    move_path.RemoveAt(0);
                    if (move_path.Count <= 0)  // 转为停止
                    {
                        speed = 0;
                        move_to_stop_remain_time = 76;
                    }
                    else
                    {
                        speed = (int)(basic_speed / map.GetHexCosts(cur_hex / 100, cur_hex % 100, MoveMode.Fly)[move_path[0]]);
                    }
                }
            }
            // 停止机动
            if (flag_force_stop)
            {
                if (speed == 0)
                {
                    if (can_to_move)
                    {
                        flag_force_stop = false;
                    }
                }
                else if (cur_pos <= 0)
                {
                    if (move_path == null) move_path = new List<int>();
                    else move_path.Clear();
                    speed = 0;
                    move_to_stop_remain_time = 76;
                    can_to_move = false;
                }
            }
            // 75秒倒计时
            if (move_to_stop_remain_time > 0)  // 停止倒计时
            {
                move_to_stop_remain_time--;
                if (move_to_stop_remain_time <= 0)
                {
                    can_to_move = true;
                    flag_force_stop = false;
                    stop = true;
                }
            }            
        }
        private void UpdataMoveAttris(IJudgeResult judge_result, Map map)
        {
            if (judge_result.ActionType != ActionType.Move)
            {
                return;
            }

            MoveJudgeResult moveJudgeResult = (MoveJudgeResult)judge_result;
            //修改算子属性
            speed = (int)(basic_speed / map.GetHexCosts(cur_hex / 100, cur_hex % 100, MoveMode.Fly)[moveJudgeResult.MovePath[0]]);
            stop = false;
            move_path = moveJudgeResult.MovePath;
            move_to_stop_remain_time = 0;
        }
        private void UpdataStopMoveAttris(IJudgeResult judge_result)
        {
            if (judge_result.ActionType != ActionType.StopMove)
            {
                return;
            }
            flag_force_stop = true;
        }
        private void UpdataSeeEnemyAttris(List<IOperator> oprs, Map map)
        {
            if (observe_distance == null) return;

                if (see_enemy_bop_ids == null) see_enemy_bop_ids = new List<int>();
            else see_enemy_bop_ids.Clear();
            for (int i = 0; i < oprs.Count; i++)
            {
                if (!typeof(ICommonAttris).IsAssignableFrom(oprs[i].GetType()) ||
                    !typeof(IMoveAttris).IsAssignableFrom(oprs[i].GetType())) continue;

                Color enemy_color = (Color)oprs[i].GetType().GetProperty("Color").GetValue(oprs[i]);
                OprType enemy_type = (OprType)oprs[i].GetType().GetProperty("Type").GetValue(oprs[i]);
                int enemy_hex = (int)oprs[i].GetType().GetProperty("CurHex").GetValue(oprs[i]);
                OprSubType enemy_sub_type = (OprSubType)oprs[i].GetType().GetProperty("Subtype").GetValue(oprs[i]);
                MoveStateType enemy_move_state = (MoveStateType)oprs[i].GetType().GetProperty("MoveState").GetValue(oprs[i]);

                if (color == enemy_color) continue;

                if (map.CanSeeTerrain(type, enemy_type, cur_hex, enemy_hex, enemy_sub_type, observe_distance, enemy_move_state))
                {
                    see_enemy_bop_ids.Add(oprs[i].ObjID);
                }
            }
        }
    }
}
